<#assign object = doc.object>
package ${object.package}.gwt.client;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import org.gwt.beansbinding.core.client.AbstractBindingListener;
import org.gwt.beansbinding.core.client.BeanProperty;
import org.gwt.beansbinding.core.client.Binding;
import org.gwt.beansbinding.core.client.BindingGroup;
import org.gwt.beansbinding.core.client.Bindings;
import org.gwt.beansbinding.core.client.Validator;
import org.gwt.beansbinding.core.client.AutoBinding.UpdateStrategy;
import org.gwt.beansbinding.core.client.Binding.SyncFailure;
import org.gwt.beansbinding.core.client.Binding.SyncFailureType;
import org.gwt.beansbinding.core.client.ext.BeanAdapterFactory;
import org.gwt.beansbinding.core.client.util.GWTBeansBinding;
import org.gwt.beansbinding.observablecollections.client.ObservableCollections;
import org.gwt.beansbinding.ui.client.GWTBindings;
import org.gwt.beansbinding.ui.client.GridBinding;
import org.gwt.beansbinding.ui.client.adapters.HTMLTableAdapterProvider;
import org.gwt.beansbinding.ui.client.adapters.HasTextAdapterProvider;
import org.gwt.beansbinding.ui.client.adapters.ListBoxAdapterProvider;
import ${object.package}.gwt.client.model.${object.name};

import com.google.gwt.core.client.GWT;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.http.client.Request;
import com.google.gwt.http.client.RequestBuilder;
import com.google.gwt.http.client.RequestCallback;
import com.google.gwt.http.client.RequestException;
import com.google.gwt.http.client.Response;
import com.google.gwt.http.client.URL;
import com.google.gwt.i18n.client.DateTimeFormat;
import com.google.gwt.json.client.JSONArray;
import com.google.gwt.json.client.JSONObject;
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.DecoratorPanel;
import com.google.gwt.user.client.ui.FlexTable;
import com.google.gwt.user.client.ui.FlowPanel;
import com.google.gwt.user.client.ui.Grid;
import com.google.gwt.user.client.ui.HasHorizontalAlignment;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.ListBox;
import com.google.gwt.user.client.ui.PushButton;
import com.google.gwt.user.client.ui.TextBox;
import com.google.gwt.user.client.ui.FlexTable.FlexCellFormatter;
import com.google.gwt.user.client.ui.HTMLTable.Cell;
import com.smartgwt.client.util.JSON;
import com.smartgwt.client.util.SC;

public class ${object.name}ViewPanel extends Composite {
	static {
		GWTBeansBinding.init();

		// Register all Adapters used in code
		BeanAdapterFactory.addProvider(new HasTextAdapterProvider());
		BeanAdapterFactory.addProvider(new HTMLTableAdapterProvider());
		BeanAdapterFactory.addProvider(new ListBoxAdapterProvider());
	}

	private ${object.name} ${object.name?uncap_first} = new ${object.name}();

	private int selectedRow = -1;

	boolean isUpdate = false;

	List<${object.name}> ${object.name?uncap_first}s = ObservableCollections
			.observableList(new ArrayList<${object.name}>());

	public ${object.name}ViewPanel() {

		String url = URL.encode(GWT.getModuleBaseURL()
				+ "${object.name?uncap_first}Operations.do?_operationType=fetch");

		final Grid grid = new Grid();
		grid.setCellSpacing(0);
		grid.setBorderWidth(1);

		addSimpleSelectionModel(grid);
		
		RequestBuilder builder = new RequestBuilder(RequestBuilder.GET, url);
		builder.setCallback(new RequestCallback() {
			public void onError(Request request, Throwable exception) {
				SC.warn("upgrade failed!");
			}

			public void onResponseReceived(Request request, Response response) {
				JSONObject object = new JSONObject(JSON.decode(response
						.getText()));
				JSONArray json${object.name}s = object.get("response").isObject().get(
						"data").isArray();
				for (int i = 0; i < json${object.name}s.size(); i++) {
					JSONObject value = json${object.name}s.get(i).isObject();
					${object.name} ${object.name?uncap_first} = new ${object.name}();
					copyValue(${object.name?uncap_first}, value);
					${object.name?uncap_first}s.add(${object.name?uncap_first});
				}
				GridBinding<${object.name}, List<${object.name}>, Grid> gridBinding = GWTBindings
						.createGridBinding(UpdateStrategy.READ, ${object.name?uncap_first}s, grid);

				// define the property to be used to derive list elements
				BeanProperty<${object.name}, Long> idP = BeanProperty.create("id");
				gridBinding.addColumnBinding(idP).setColumnName("id");
				<#list object.attributes?children as att>
	  				<#if att?node_name != "set" && att?node_type == "element">
	  					<#if att?node_name == "xml">
	  			// TODO
	  					<#elseif att?node_name == "date" || att?node_name == "datetime">
	  			BeanProperty<${object.name}, Date> ${att.@name}P = BeanProperty
						.create("${att.@name}");
				gridBinding.addColumnBinding(${att.@name}P).setColumnName(
						"${att.@name}");
						<#elseif att?node_name == "enum">
				BeanProperty<${object.name}, ${object.name}.${att.@class}> ${att.@class?uncap_first}P = BeanProperty.create("${att.@class?uncap_first}");
				gridBinding.addColumnBinding(${att.@class?uncap_first}P).setColumnName(
						"${att.@class?uncap_first}");
						<#elseif att?node_name == "object">
				// TODO
						<#elseif att?node_name == "html" || att?node_name == "string">		
	  			BeanProperty<${object.name}, String> ${att.@name}P = BeanProperty
						.create("${att.@name}");
				gridBinding.addColumnBinding(${att.@name}P).setColumnName(
						"${att.@name}");
						<#elseif att?node_name == "boolean">
				BeanProperty<${object.name}, Boolean> ${att.@name}P = BeanProperty
						.create("${att.@name}");
				gridBinding.addColumnBinding(${att.@name}P).setColumnName(
						"${att.@name}");
						<#else>
				BeanProperty<${object.name}, ${att?node_name?cap_first}> ${att.@name}P = BeanProperty
						.create("${att.@name}");
				gridBinding.addColumnBinding(${att.@name}P).setColumnName(
						"${att.@name}");	
						</#if>
	  				</#if>
				</#list>
				BeanProperty<${object.name}, Date> creationDateP = BeanProperty
						.create("creationDate");
				gridBinding.addColumnBinding(creationDateP).setColumnName(
						"creationDate");		
				BeanProperty<${object.name}, Date> updateDateP = BeanProperty
						.create("updateDate");
				gridBinding.addColumnBinding(updateDateP).setColumnName(
						"updateDate");
				gridBinding.bind();

			}
		});
		try {
			builder.send();
		} catch (RequestException e) {
			e.printStackTrace();
		}
		
		BindingGroup bindingGroup = new BindingGroup();
		// bind to the selection of grid
		
		final TextBox id = new TextBox();
		id.setReadOnly(true);

		Binding<Grid, ${object.name}, TextBox, String> idBinding = Bindings
				.createAutoBinding(UpdateStrategy.READ_WRITE, grid,
						BeanProperty.<Grid, ${object.name}> create("selectedItem.id"),
						id, BeanProperty.<TextBox, String> create("text"));
		bindingGroup.addBinding(idBinding);

		<#list object.attributes?children as att>
	  		<#if att?node_name != "set" && att?node_type == "element">
	  			<#if att?node_name == "xml">
	  	//TODO
	  			<#elseif att?node_name == "date" || att?node_name == "datetime">
	  			<#elseif att?node_name == "enum">
	  			<#elseif att?node_name == "object">
	  			<#elseif att?node_name == "html" || att?node_name == "string">
	  	final TextBox ${att.@name} = new TextBox();

		Binding<Grid, ${object.name}, TextBox, String> ${att.@name}GridBinding = Bindings
				.createAutoBinding(UpdateStrategy.READ_WRITE, grid,
						BeanProperty
								.<Grid, ${object.name}> create("selectedItem.${att.@name}"),
						${att.@name}, BeanProperty.<TextBox, String> create("text"));

		Binding<${object.name}, String, TextBox, String> ${att.@name}Binding = Bindings
				.createAutoBinding(UpdateStrategy.READ_WRITE, ${object.name?uncap_first},
						BeanProperty.<${object.name}, String> create("${att.@name}"),
						${att.@name}, BeanProperty.<TextBox, String> create("text"));
		bindingGroup.addBinding(${att.@name}GridBinding);
		bindingGroup.addBinding(${att.@name}Binding);
	  			<#elseif att?node_name == "boolean">
	  	final TextBox ${att.@name} = new TextBox();
	  	Binding<Grid, ${object.name}, TextBox, Boolean> ${att.@name}GridBinding = Bindings
				.createAutoBinding(UpdateStrategy.READ_WRITE, grid,
						BeanProperty
								.<Grid, ${object.name}> create("selectedItem.${att.@name}"),
						${att.@name}, BeanProperty.<TextBox, Boolean> create("text"));

		Binding<${object.name}, String, TextBox, Boolean> ${att.@name}Binding = Bindings
				.createAutoBinding(UpdateStrategy.READ_WRITE, ${object.name?uncap_first},
						BeanProperty.<${object.name}, String> create("${att.@name}"),
						${att.@name}, BeanProperty.<TextBox, Boolean> create("text"));
		bindingGroup.addBinding(${att.@name}GridBinding);
		bindingGroup.addBinding(${att.@name}Binding);
				<#else>
		final TextBox ${att.@name} = new TextBox();
		Binding<Grid, ${object.name}, TextBox, ${att?node_name?cap_first}> ${att.@name}GridBinding = Bindings
				.createAutoBinding(UpdateStrategy.READ_WRITE, grid,
						BeanProperty
								.<Grid, ${object.name}> create("selectedItem.${att.@name}"),
						${att.@name}, BeanProperty.<TextBox, ${att?node_name?cap_first}> create("text"));

		Binding<${object.name}, ${att?node_name?cap_first}, TextBox, ${att?node_name?cap_first}> ${att.@name}Binding = Bindings
				.createAutoBinding(UpdateStrategy.READ_WRITE, ${object.name?uncap_first},
						BeanProperty.<${object.name}, ${att?node_name?cap_first}> create("${att.@name}"),
						${att.@name}, BeanProperty.<TextBox, ${att?node_name?cap_first}> create("text"));
		bindingGroup.addBinding(${att.@name}GridBinding);
		bindingGroup.addBinding(${att.@name}Binding);
				</#if>
	  		</#if>
		</#list>

		bindingGroup.addBindingListener(new AbstractBindingListener() {
			@Override
			public void syncFailed(Binding binding, SyncFailure failure) {
				SyncFailureType type = failure.getType();
				if (type == SyncFailureType.VALIDATION_FAILED) {
					TextBox textBox = (TextBox) binding.getTargetObject();
					textBox.getElement().getStyle().setBackgroundColor("red");
					textBox.setFocus(true);

					Window
							.alert(failure.getValidationResult()
									.getDescription());
				}
			}

			@Override
			public void synced(Binding binding) {
				TextBox textBox = (TextBox) binding.getTargetObject();
				textBox.getElement().getStyle().setBackgroundColor("white");
			}
		});

		bindingGroup.bind();

		PushButton btn1 = new PushButton("Add Or Update");
		btn1.addClickHandler(new ClickHandler() {

			public void onClick(ClickEvent arg0) {
				if (id.getValue() != null && id.getValue().length() > 0) {
					${object.name?uncap_first}.setId(Long.valueOf(id.getValue()));
					isUpdate = true;
				}
				<#list object.attributes?children as att>
			  		<#if att?node_name != "set" && att?node_type == "element">
			  			<#if att?node_name == "xml">
			  	//TODO
			  			<#elseif att?node_name == "date" || att?node_name == "datetime">
			  			<#elseif att?node_name == "enum">
			  			<#elseif att?node_name == "object">
			  			<#elseif att?node_name == "html" || att?node_name == "string">
					${object.name?uncap_first}.set${att.@name?cap_first}(${att.@name}.getValue());
			  			<#elseif att?node_name == "boolean">
					${object.name?uncap_first}.set${att.@name?cap_first}(Boolean.valueOf(${att.@name}.getValue()));
						<#elseif att?node_name == "integer">
				if (${att.@name}.getValue() != null
						&& ${att.@name}.getValue().length() > 0)
					${object.name?uncap_first}.set${att.@name?cap_first}(Integer.parseInt(${att.@name}.getValue()));
						<#elseif att?node_name == "long">
				if (${att.@name}.getValue() != null
						&& ${att.@name}.getValue().length() > 0)
					${object.name?uncap_first}.set${att.@name?cap_first}(Long.valueOf(${att.@name}.getValue()));
						<#else>
						</#if>
			  		</#if>
				</#list>	
				String url = "";
				if (isUpdate) {
					url = URL.encode(GWT.getModuleBaseURL()
							+ "${object.name?uncap_first}Operations.do?_operationType=update"
							+ "&id=" + ${object.name?uncap_first}.getId()
					<#list object.attributes?children as att>
			  			<#if att?node_name != "set" && att?node_type == "element">
			  				<#if att?node_name == "xml">
			  				<#elseif att?node_name == "date" || att?node_name == "datetime">
			  				<#elseif att?node_name == "enum">
			  				<#elseif att?node_name == "object">
			  				<#elseif att?node_name == "html" || att?node_name == "string">
						    + "&${att.@name}=" + ${object.name?uncap_first}.get${att.@name?cap_first}()
						    <#elseif att?node_name == "boolean">
						    + "&${att.@name}=" + ${object.name?uncap_first}.get${att.@name?cap_first}()
						    <#elseif att?node_name == "integer">
						    + "&${att.@name}=" + ${object.name?uncap_first}.get${att.@name?cap_first}()
						    <#elseif att?node_name == "long">
						    + "&${att.@name}=" + ${object.name?uncap_first}.get${att.@name?cap_first}()
						    <#else>
							</#if>
						</#if>
					</#list>
							);
				} else {
					url = URL.encode(GWT.getModuleBaseURL()
							+ "${object.name?uncap_first}Operations.do?_operationType=add"
					<#list object.attributes?children as att>
			  			<#if att?node_name != "set" && att?node_type == "element">
			  				<#if att?node_name == "xml">
			  				<#elseif att?node_name == "date" || att?node_name == "datetime">
			  				<#elseif att?node_name == "enum">
			  				<#elseif att?node_name == "object">
			  				<#elseif att?node_name == "html" || att?node_name == "string">
						    + "&${att.@name}=" + ${object.name?uncap_first}.get${att.@name?cap_first}()
						    <#elseif att?node_name == "boolean">
						    + "&${att.@name}=" + ${object.name?uncap_first}.get${att.@name?cap_first}()
						    <#elseif att?node_name == "integer">
						    + "&${att.@name}=" + ${object.name?uncap_first}.get${att.@name?cap_first}()
						    <#elseif att?node_name == "long">
						    + "&${att.@name}=" + ${object.name?uncap_first}.get${att.@name?cap_first}()
						    <#else>
							</#if>
						</#if>
					</#list>
							);
				}
				RequestBuilder builder = new RequestBuilder(RequestBuilder.GET,
						url);
				builder.setCallback(new RequestCallback() {
					public void onError(Request request, Throwable exception) {
						SC.warn("upgrade failed!");
					}

					public void onResponseReceived(Request request,
							Response response) {
						JSONObject object = new JSONObject(JSON.decode(response
								.getText()));
						${object.name} new${object.name} = new ${object.name}();
						if (!isUpdate) {
							copyValue(new${object.name}, object);
							${object.name?uncap_first}s.add(new${object.name});
						}
					}
				});
				try {
					builder.send();
				} catch (RequestException e) {
					e.printStackTrace();
				}
			}

		});
//		PushButton btn2 = new PushButton("Reset");
//		btn2.addClickHandler(new ClickHandler() {

//			public void onClick(ClickEvent arg0) {
//				id.setValue(null);
//				userName.setValue(null);
//				password.setValue(null);
//				userAge.setValue(null);
//				if (selectedRow != -1) {
//					DOM.setStyleAttribute(grid.getRowFormatter().getElement(
//							selectedRow), "backgroundColor", "");
//				}
//				selectedRow = -1;
//			}

//		});

		PushButton btn3 = new PushButton("Delete");
		btn3.addClickHandler(new ClickHandler() {

			public void onClick(ClickEvent arg0) {
				if (selectedRow == -1) {
					Window.alert("You must select a record first!");
					return;
				}
				Long id = Long.valueOf(grid.getText(selectedRow, 0));
				if (!Window.confirm("You will delete ${object.name} with id:" + id))
					return;
				String url = URL.encode(GWT.getModuleBaseURL()
						+ "${object.name?uncap_first}Operations.do?_operationType=remove&id="
						+ grid.getText(selectedRow, 0));
				//user.setId(id);
				RequestBuilder builder = new RequestBuilder(RequestBuilder.GET,
						url);
				builder.setCallback(new RequestCallback() {
					public void onError(Request request, Throwable exception) {
						Window.alert("Delete failed!");
					}

					public void onResponseReceived(Request request,
							Response response) {
						Window.alert("Delete success!");
						${object.name?uncap_first}s.remove(selectedRow);
					}
				});
				try {
					builder.send();
				} catch (RequestException e) {
					e.printStackTrace();
				}
			}

		});

		FlowPanel panel = new FlowPanel();
		grid.setWidth("100%");
		panel.add(grid);
		FlexTable form = new FlexTable();
		form.setCellSpacing(6);
		FlexCellFormatter cellFormatter = form.getFlexCellFormatter();
		// Add a title to the form
		form.setHTML(0, 0, "Add Or Update Form");
		cellFormatter.setColSpan(0, 0, 2);
		cellFormatter.setHorizontalAlignment(0, 0,
				HasHorizontalAlignment.ALIGN_CENTER);

		// Add some standard form options
		form.setHTML(1, 0, "id:");
		form.setWidget(1, 1, id);
		<#assign position = 1>
		<#list object.attributes?children as att>
			<#if att?node_name != "set" && att?node_type == "element">
				<#if att?node_name == "xml">
			  	<#elseif att?node_name == "date" || att?node_name == "datetime">
			  	<#elseif att?node_name == "enum">
			  	<#elseif att?node_name == "object">
			  	<#elseif att?node_name == "html" || att?node_name == "string">
				<#assign position = position + 1>
		form.setHTML(${position}, 0, "${att.@name}:");
		form.setWidget(${position}, 1, ${att.@name});
				<#elseif att?node_name == "boolean">
				<#assign position = position + 1>
		form.setHTML(${position}, 0, "${att.@name}:");
		form.setWidget(${position}, 1, ${att.@name});		   
				<#elseif att?node_name == "integer">
				<#assign position = position + 1>
		form.setHTML(${position}, 0, "${att.@name}:");
		form.setWidget(${position}, 1, ${att.@name});		    
				<#elseif att?node_name == "long">
				<#assign position = position + 1>
		form.setHTML(${position}, 0, "${att.@name}:");
		form.setWidget(${position}, 1, ${att.@name});		    
				<#else>
				</#if>
			</#if>
		</#list>

		// Wrap the content in a DecoratorPanel
		DecoratorPanel decPanel = new DecoratorPanel();
		decPanel.setWidget(form);
		panel.add(decPanel);
		HorizontalPanel hPanel = new HorizontalPanel();
		btn1.setWidth("150");
		hPanel.add(btn1);
//		btn2.setWidth("100");
//		hPanel.add(btn2);
		btn3.setWidth("100");
		hPanel.add(btn3);
		panel.add(hPanel);

		this.initWidget(panel);
	}

	private void addSimpleSelectionModel(final Grid grid) {
		grid.addClickHandler(new ClickHandler() {
			public void onClick(ClickEvent event) {
				Cell cell = grid.getCellForEvent(event);
				if (cell != null) {
					if (selectedRow != -1) {
						DOM
								.setStyleAttribute(grid.getRowFormatter()
										.getElement(selectedRow),
										"backgroundColor", "");
					}
					selectedRow = cell.getRowIndex();
					if (selectedRow != -1) {
						DOM.setStyleAttribute(grid.getRowFormatter()
								.getElement(selectedRow), "backgroundColor",
								"#adcce7");
					}
				}
			}
		});
	}

	private void copyValue(${object.name} ${object.name?uncap_first}, JSONObject value) {
		if (value.get("id") != null
				&& !value.get("id").toString().equalsIgnoreCase("null"))
			${object.name?uncap_first}.setId(Long.valueOf(value.get("id").toString()));
		<#list object.attributes?children as att>
	  		<#if att?node_name != "set" && att?node_type == "element">
	  			<#if att?node_name == "xml">
	  	//TODO
	  			<#elseif att?node_name == "date" || att?node_name == "datetime">
	  	if (value.get("${att.@name}") != null
				&& !value.get("${att.@name}").toString().equalsIgnoreCase("null"))
			${object.name?uncap_first}.set${att.@name?cap_first}(DateTimeFormat.getFormat("yyyy-MM-dd").parse(
					value.get("${att.@name}").toString()));
	  			<#elseif att?node_name == "enum">
	  	if (value.get("${att.@class?uncap_first}") != null
				&& !value.get("${att.@class?uncap_first}").toString().equalsIgnoreCase("null"))
			${object.name?uncap_first}.set${att.@class}(${object.name}.${att.@class}.valueOfNullSafe(value.get("${att.@class?uncap_first}").isString().stringValue()));
	  			<#elseif att?node_name == "object">
	  			<#elseif att?node_name == "html" || att?node_name == "string">
	  	if (value.get("${att.@name}") != null
				&& !value.get("${att.@name}").toString().equalsIgnoreCase("null"))
			${object.name?uncap_first}.set${att.@name?cap_first}(value.get("${att.@name}").isString().stringValue());
	  			<#elseif att?node_name == "boolean">
	  	if (value.get("${att.@name}") != null
				&& !value.get("${att.@name}").toString().equalsIgnoreCase("null"))
			${object.name?uncap_first}.set${att.@name?cap_first}(Boolean.valueOf(value.get("${att.@name}").isString().stringValue()));
				<#elseif att?node_name == "integer">
		if (value.get("${att.@name}") != null
				&& !value.get("${att.@name}").toString().equalsIgnoreCase("null"))
			${object.name?uncap_first}.set${att.@name?cap_first}(Integer.parseInt(value.get("${att.@name}").toString()));
				<#elseif att?node_name == "long">
		if (value.get("${att.@name}") != null
				&& !value.get("${att.@name}").toString().equalsIgnoreCase("null"))
			${object.name?uncap_first}.set${att.@name?cap_first}(Long.valueOf(value.get("${att.@name}").toString()));
				<#else>
				</#if>
	  		</#if>
		</#list>	
		if (value.get("creationDate") != null
				&& !value.get("creationDate").toString().equalsIgnoreCase(
						"null"))
			${object.name?uncap_first}.setCreationDate(new Date(value.get("creationDate").isString()
					.stringValue().replaceAll("-", "/").substring(0, 19)));
		if (value.get("updateDate") != null
				&& !value.get("updateDate").toString().equalsIgnoreCase("null"))
			${object.name?uncap_first}.setUpdateDate(new Date(value.get("creationDate").isString()
					.stringValue().replaceAll("-", "/").substring(0, 19)));
	}
}
